summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/input_common/helpers/joycon_protocol/calibration.cpp210
-rw-r--r--src/input_common/helpers/joycon_protocol/calibration.h18
-rw-r--r--src/input_common/helpers/joycon_protocol/common_protocol.cpp18
-rw-r--r--src/input_common/helpers/joycon_protocol/common_protocol.h23
-rw-r--r--src/input_common/helpers/joycon_protocol/generic_functions.cpp8
-rw-r--r--src/input_common/helpers/joycon_protocol/joycon_types.h52
-rw-r--r--src/shader_recompiler/backend/glasm/emit_glasm.cpp2
-rw-r--r--src/shader_recompiler/backend/glasm/emit_glasm_bitwise_conversion.cpp4
-rw-r--r--src/shader_recompiler/backend/glasm/emit_glasm_image.cpp11
-rw-r--r--src/shader_recompiler/backend/glasm/emit_glasm_instructions.h1
-rw-r--r--src/shader_recompiler/backend/glsl/emit_glsl_bitwise_conversion.cpp4
-rw-r--r--src/shader_recompiler/backend/glsl/emit_glsl_image.cpp17
-rw-r--r--src/shader_recompiler/backend/glsl/emit_glsl_instructions.h1
-rw-r--r--src/shader_recompiler/backend/glsl/glsl_emit_context.cpp49
-rw-r--r--src/shader_recompiler/backend/spirv/emit_spirv_bitwise_conversion.cpp4
-rw-r--r--src/shader_recompiler/backend/spirv/emit_spirv_instructions.h1
-rw-r--r--src/shader_recompiler/frontend/ir/ir_emitter.cpp5
-rw-r--r--src/shader_recompiler/frontend/ir/opcodes.h1
-rw-r--r--src/shader_recompiler/frontend/ir/opcodes.inc1
-rw-r--r--src/shader_recompiler/frontend/ir/type.h31
-rw-r--r--src/shader_recompiler/frontend/ir/value.cpp3
-rw-r--r--src/shader_recompiler/frontend/ir/value.h1
-rw-r--r--src/shader_recompiler/ir_opt/texture_pass.cpp8
-rw-r--r--src/video_core/texture_cache/image_info.cpp4
-rw-r--r--src/video_core/texture_cache/samples_helper.h44
-rw-r--r--src/yuzu/configuration/input_profiles.cpp7
-rw-r--r--src/yuzu/multiplayer/direct_connect.cpp21
-rw-r--r--src/yuzu/multiplayer/direct_connect.ui23
-rw-r--r--src/yuzu/multiplayer/validation.h25
29 files changed, 371 insertions, 226 deletions
diff --git a/src/input_common/helpers/joycon_protocol/calibration.cpp b/src/input_common/helpers/joycon_protocol/calibration.cpp
index f6e7e97d5..d8f040f75 100644
--- a/src/input_common/helpers/joycon_protocol/calibration.cpp
+++ b/src/input_common/helpers/joycon_protocol/calibration.cpp
@@ -13,33 +13,33 @@ CalibrationProtocol::CalibrationProtocol(std::shared_ptr<JoyconHandle> handle)
DriverResult CalibrationProtocol::GetLeftJoyStickCalibration(JoyStickCalibration& calibration) {
ScopedSetBlocking sb(this);
- std::vector<u8> buffer;
DriverResult result{DriverResult::Success};
+ JoystickLeftSpiCalibration spi_calibration{};
+ bool has_user_calibration = false;
calibration = {};
- result = ReadSPI(CalAddr::USER_LEFT_MAGIC, sizeof(u16), buffer);
-
if (result == DriverResult::Success) {
- const bool has_user_calibration = buffer[0] == 0xB2 && buffer[1] == 0xA1;
- if (has_user_calibration) {
- result = ReadSPI(CalAddr::USER_LEFT_DATA, 9, buffer);
- } else {
- result = ReadSPI(CalAddr::FACT_LEFT_DATA, 9, buffer);
- }
+ result = HasUserCalibration(SpiAddress::USER_LEFT_MAGIC, has_user_calibration);
}
- if (result == DriverResult::Success) {
- calibration.x.max = static_cast<u16>(((buffer[1] & 0x0F) << 8) | buffer[0]);
- calibration.y.max = static_cast<u16>((buffer[2] << 4) | (buffer[1] >> 4));
- calibration.x.center = static_cast<u16>(((buffer[4] & 0x0F) << 8) | buffer[3]);
- calibration.y.center = static_cast<u16>((buffer[5] << 4) | (buffer[4] >> 4));
- calibration.x.min = static_cast<u16>(((buffer[7] & 0x0F) << 8) | buffer[6]);
- calibration.y.min = static_cast<u16>((buffer[8] << 4) | (buffer[7] >> 4));
+ // Read User defined calibration
+ if (result == DriverResult::Success && has_user_calibration) {
+ result = ReadSPI(SpiAddress::USER_LEFT_DATA, spi_calibration);
}
- // Nintendo fix for drifting stick
- // result = ReadSPI(0x60, 0x86 ,buffer, 16);
- // calibration.deadzone = (u16)((buffer[4] << 8) & 0xF00 | buffer[3]);
+ // Read Factory calibration
+ if (result == DriverResult::Success && !has_user_calibration) {
+ result = ReadSPI(SpiAddress::FACT_LEFT_DATA, spi_calibration);
+ }
+
+ if (result == DriverResult::Success) {
+ calibration.x.center = GetXAxisCalibrationValue(spi_calibration.center);
+ calibration.y.center = GetYAxisCalibrationValue(spi_calibration.center);
+ calibration.x.min = GetXAxisCalibrationValue(spi_calibration.min);
+ calibration.y.min = GetYAxisCalibrationValue(spi_calibration.min);
+ calibration.x.max = GetXAxisCalibrationValue(spi_calibration.max);
+ calibration.y.max = GetYAxisCalibrationValue(spi_calibration.max);
+ }
// Set a valid default calibration if data is missing
ValidateCalibration(calibration);
@@ -49,33 +49,33 @@ DriverResult CalibrationProtocol::GetLeftJoyStickCalibration(JoyStickCalibration
DriverResult CalibrationProtocol::GetRightJoyStickCalibration(JoyStickCalibration& calibration) {
ScopedSetBlocking sb(this);
- std::vector<u8> buffer;
DriverResult result{DriverResult::Success};
+ JoystickRightSpiCalibration spi_calibration{};
+ bool has_user_calibration = false;
calibration = {};
- result = ReadSPI(CalAddr::USER_RIGHT_MAGIC, sizeof(u16), buffer);
-
if (result == DriverResult::Success) {
- const bool has_user_calibration = buffer[0] == 0xB2 && buffer[1] == 0xA1;
- if (has_user_calibration) {
- result = ReadSPI(CalAddr::USER_RIGHT_DATA, 9, buffer);
- } else {
- result = ReadSPI(CalAddr::FACT_RIGHT_DATA, 9, buffer);
- }
+ result = HasUserCalibration(SpiAddress::USER_RIGHT_MAGIC, has_user_calibration);
}
- if (result == DriverResult::Success) {
- calibration.x.center = static_cast<u16>(((buffer[1] & 0x0F) << 8) | buffer[0]);
- calibration.y.center = static_cast<u16>((buffer[2] << 4) | (buffer[1] >> 4));
- calibration.x.min = static_cast<u16>(((buffer[4] & 0x0F) << 8) | buffer[3]);
- calibration.y.min = static_cast<u16>((buffer[5] << 4) | (buffer[4] >> 4));
- calibration.x.max = static_cast<u16>(((buffer[7] & 0x0F) << 8) | buffer[6]);
- calibration.y.max = static_cast<u16>((buffer[8] << 4) | (buffer[7] >> 4));
+ // Read User defined calibration
+ if (result == DriverResult::Success && has_user_calibration) {
+ result = ReadSPI(SpiAddress::USER_RIGHT_DATA, spi_calibration);
+ }
+
+ // Read Factory calibration
+ if (result == DriverResult::Success && !has_user_calibration) {
+ result = ReadSPI(SpiAddress::FACT_RIGHT_DATA, spi_calibration);
}
- // Nintendo fix for drifting stick
- // buffer = ReadSPI(0x60, 0x98 , 16);
- // joystick.deadzone = (u16)((buffer[4] << 8) & 0xF00 | buffer[3]);
+ if (result == DriverResult::Success) {
+ calibration.x.center = GetXAxisCalibrationValue(spi_calibration.center);
+ calibration.y.center = GetYAxisCalibrationValue(spi_calibration.center);
+ calibration.x.min = GetXAxisCalibrationValue(spi_calibration.min);
+ calibration.y.min = GetYAxisCalibrationValue(spi_calibration.min);
+ calibration.x.max = GetXAxisCalibrationValue(spi_calibration.max);
+ calibration.y.max = GetYAxisCalibrationValue(spi_calibration.max);
+ }
// Set a valid default calibration if data is missing
ValidateCalibration(calibration);
@@ -85,39 +85,41 @@ DriverResult CalibrationProtocol::GetRightJoyStickCalibration(JoyStickCalibratio
DriverResult CalibrationProtocol::GetImuCalibration(MotionCalibration& calibration) {
ScopedSetBlocking sb(this);
- std::vector<u8> buffer;
DriverResult result{DriverResult::Success};
+ ImuSpiCalibration spi_calibration{};
+ bool has_user_calibration = false;
calibration = {};
- result = ReadSPI(CalAddr::USER_IMU_MAGIC, sizeof(u16), buffer);
-
if (result == DriverResult::Success) {
- const bool has_user_calibration = buffer[0] == 0xB2 && buffer[1] == 0xA1;
- if (has_user_calibration) {
- result = ReadSPI(CalAddr::USER_IMU_DATA, sizeof(IMUCalibration), buffer);
- } else {
- result = ReadSPI(CalAddr::FACT_IMU_DATA, sizeof(IMUCalibration), buffer);
- }
+ result = HasUserCalibration(SpiAddress::USER_IMU_MAGIC, has_user_calibration);
+ }
+
+ // Read User defined calibration
+ if (result == DriverResult::Success && has_user_calibration) {
+ result = ReadSPI(SpiAddress::USER_IMU_DATA, spi_calibration);
+ }
+
+ // Read Factory calibration
+ if (result == DriverResult::Success && !has_user_calibration) {
+ result = ReadSPI(SpiAddress::FACT_IMU_DATA, spi_calibration);
}
if (result == DriverResult::Success) {
- IMUCalibration device_calibration{};
- memcpy(&device_calibration, buffer.data(), sizeof(IMUCalibration));
- calibration.accelerometer[0].offset = device_calibration.accelerometer_offset[0];
- calibration.accelerometer[1].offset = device_calibration.accelerometer_offset[1];
- calibration.accelerometer[2].offset = device_calibration.accelerometer_offset[2];
+ calibration.accelerometer[0].offset = spi_calibration.accelerometer_offset[0];
+ calibration.accelerometer[1].offset = spi_calibration.accelerometer_offset[1];
+ calibration.accelerometer[2].offset = spi_calibration.accelerometer_offset[2];
- calibration.accelerometer[0].scale = device_calibration.accelerometer_scale[0];
- calibration.accelerometer[1].scale = device_calibration.accelerometer_scale[1];
- calibration.accelerometer[2].scale = device_calibration.accelerometer_scale[2];
+ calibration.accelerometer[0].scale = spi_calibration.accelerometer_scale[0];
+ calibration.accelerometer[1].scale = spi_calibration.accelerometer_scale[1];
+ calibration.accelerometer[2].scale = spi_calibration.accelerometer_scale[2];
- calibration.gyro[0].offset = device_calibration.gyroscope_offset[0];
- calibration.gyro[1].offset = device_calibration.gyroscope_offset[1];
- calibration.gyro[2].offset = device_calibration.gyroscope_offset[2];
+ calibration.gyro[0].offset = spi_calibration.gyroscope_offset[0];
+ calibration.gyro[1].offset = spi_calibration.gyroscope_offset[1];
+ calibration.gyro[2].offset = spi_calibration.gyroscope_offset[2];
- calibration.gyro[0].scale = device_calibration.gyroscope_scale[0];
- calibration.gyro[1].scale = device_calibration.gyroscope_scale[1];
- calibration.gyro[2].scale = device_calibration.gyroscope_scale[2];
+ calibration.gyro[0].scale = spi_calibration.gyroscope_scale[0];
+ calibration.gyro[1].scale = spi_calibration.gyroscope_scale[1];
+ calibration.gyro[2].scale = spi_calibration.gyroscope_scale[2];
}
ValidateCalibration(calibration);
@@ -127,10 +129,12 @@ DriverResult CalibrationProtocol::GetImuCalibration(MotionCalibration& calibrati
DriverResult CalibrationProtocol::GetRingCalibration(RingCalibration& calibration,
s16 current_value) {
+ constexpr s16 DefaultRingRange{800};
+
// TODO: Get default calibration form ring itself
if (ring_data_max == 0 && ring_data_min == 0) {
- ring_data_max = current_value + 800;
- ring_data_min = current_value - 800;
+ ring_data_max = current_value + DefaultRingRange;
+ ring_data_min = current_value - DefaultRingRange;
ring_data_default = current_value;
}
ring_data_max = std::max(ring_data_max, current_value);
@@ -143,42 +147,72 @@ DriverResult CalibrationProtocol::GetRingCalibration(RingCalibration& calibratio
return DriverResult::Success;
}
+DriverResult CalibrationProtocol::HasUserCalibration(SpiAddress address,
+ bool& has_user_calibration) {
+ MagicSpiCalibration spi_magic{};
+ const DriverResult result{ReadSPI(address, spi_magic)};
+ has_user_calibration = false;
+ if (result == DriverResult::Success) {
+ has_user_calibration = spi_magic.first == CalibrationMagic::USR_MAGIC_0 &&
+ spi_magic.second == CalibrationMagic::USR_MAGIC_1;
+ }
+ return result;
+}
+
+u16 CalibrationProtocol::GetXAxisCalibrationValue(std::span<u8> block) const {
+ return static_cast<u16>(((block[1] & 0x0F) << 8) | block[0]);
+}
+
+u16 CalibrationProtocol::GetYAxisCalibrationValue(std::span<u8> block) const {
+ return static_cast<u16>((block[2] << 4) | (block[1] >> 4));
+}
+
void CalibrationProtocol::ValidateCalibration(JoyStickCalibration& calibration) {
- constexpr u16 DefaultStickCenter{2048};
- constexpr u16 DefaultStickRange{1740};
+ constexpr u16 DefaultStickCenter{0x800};
+ constexpr u16 DefaultStickRange{0x6cc};
- if (calibration.x.center == 0xFFF || calibration.x.center == 0) {
- calibration.x.center = DefaultStickCenter;
- }
- if (calibration.x.max == 0xFFF || calibration.x.max == 0) {
- calibration.x.max = DefaultStickRange;
+ calibration.x.center = ValidateValue(calibration.x.center, DefaultStickCenter);
+ calibration.x.max = ValidateValue(calibration.x.max, DefaultStickRange);
+ calibration.x.min = ValidateValue(calibration.x.min, DefaultStickRange);
+
+ calibration.y.center = ValidateValue(calibration.y.center, DefaultStickCenter);
+ calibration.y.max = ValidateValue(calibration.y.max, DefaultStickRange);
+ calibration.y.min = ValidateValue(calibration.y.min, DefaultStickRange);
+}
+
+void CalibrationProtocol::ValidateCalibration(MotionCalibration& calibration) {
+ constexpr s16 DefaultAccelerometerScale{0x4000};
+ constexpr s16 DefaultGyroScale{0x3be7};
+ constexpr s16 DefaultOffset{0};
+
+ for (auto& sensor : calibration.accelerometer) {
+ sensor.scale = ValidateValue(sensor.scale, DefaultAccelerometerScale);
+ sensor.offset = ValidateValue(sensor.offset, DefaultOffset);
}
- if (calibration.x.min == 0xFFF || calibration.x.min == 0) {
- calibration.x.min = DefaultStickRange;
+ for (auto& sensor : calibration.gyro) {
+ sensor.scale = ValidateValue(sensor.scale, DefaultGyroScale);
+ sensor.offset = ValidateValue(sensor.offset, DefaultOffset);
}
+}
- if (calibration.y.center == 0xFFF || calibration.y.center == 0) {
- calibration.y.center = DefaultStickCenter;
- }
- if (calibration.y.max == 0xFFF || calibration.y.max == 0) {
- calibration.y.max = DefaultStickRange;
+u16 CalibrationProtocol::ValidateValue(u16 value, u16 default_value) const {
+ if (value == 0) {
+ return default_value;
}
- if (calibration.y.min == 0xFFF || calibration.y.min == 0) {
- calibration.y.min = DefaultStickRange;
+ if (value == 0xFFF) {
+ return default_value;
}
+ return value;
}
-void CalibrationProtocol::ValidateCalibration(MotionCalibration& calibration) {
- for (auto& sensor : calibration.accelerometer) {
- if (sensor.scale == 0) {
- sensor.scale = 0x4000;
- }
+s16 CalibrationProtocol::ValidateValue(s16 value, s16 default_value) const {
+ if (value == 0) {
+ return default_value;
}
- for (auto& sensor : calibration.gyro) {
- if (sensor.scale == 0) {
- sensor.scale = 0x3be7;
- }
+ if (value == 0xFFF) {
+ return default_value;
}
+ return value;
}
} // namespace InputCommon::Joycon
diff --git a/src/input_common/helpers/joycon_protocol/calibration.h b/src/input_common/helpers/joycon_protocol/calibration.h
index afb52a36a..c6fd0f729 100644
--- a/src/input_common/helpers/joycon_protocol/calibration.h
+++ b/src/input_common/helpers/joycon_protocol/calibration.h
@@ -53,9 +53,27 @@ public:
DriverResult GetRingCalibration(RingCalibration& calibration, s16 current_value);
private:
+ /// Returns true if the specified address corresponds to the magic value of user calibration
+ DriverResult HasUserCalibration(SpiAddress address, bool& has_user_calibration);
+
+ /// Converts a raw calibration block to an u16 value containing the x axis value
+ u16 GetXAxisCalibrationValue(std::span<u8> block) const;
+
+ /// Converts a raw calibration block to an u16 value containing the y axis value
+ u16 GetYAxisCalibrationValue(std::span<u8> block) const;
+
+ /// Ensures that all joystick calibration values are set
void ValidateCalibration(JoyStickCalibration& calibration);
+
+ /// Ensures that all motion calibration values are set
void ValidateCalibration(MotionCalibration& calibration);
+ /// Returns the default value if the value is either zero or 0xFFF
+ u16 ValidateValue(u16 value, u16 default_value) const;
+
+ /// Returns the default value if the value is either zero or 0xFFF
+ s16 ValidateValue(s16 value, s16 default_value) const;
+
s16 ring_data_max = 0;
s16 ring_data_default = 0;
s16 ring_data_min = 0;
diff --git a/src/input_common/helpers/joycon_protocol/common_protocol.cpp b/src/input_common/helpers/joycon_protocol/common_protocol.cpp
index 417d0dcc5..0ef240344 100644
--- a/src/input_common/helpers/joycon_protocol/common_protocol.cpp
+++ b/src/input_common/helpers/joycon_protocol/common_protocol.cpp
@@ -22,8 +22,8 @@ void JoyconCommonProtocol::SetNonBlocking() {
}
DriverResult JoyconCommonProtocol::GetDeviceType(ControllerType& controller_type) {
- std::vector<u8> buffer;
- const auto result = ReadSPI(CalAddr::DEVICE_TYPE, 1, buffer);
+ std::array<u8, 1> buffer{};
+ const auto result = ReadRawSPI(SpiAddress::DEVICE_TYPE, buffer);
controller_type = ControllerType::None;
if (result == DriverResult::Success) {
@@ -148,11 +148,13 @@ DriverResult JoyconCommonProtocol::SendVibrationReport(std::span<const u8> buffe
return SendData(local_buffer);
}
-DriverResult JoyconCommonProtocol::ReadSPI(CalAddr addr, u8 size, std::vector<u8>& output) {
+DriverResult JoyconCommonProtocol::ReadRawSPI(SpiAddress addr, std::span<u8> output) {
+ constexpr std::size_t HeaderSize = 20;
constexpr std::size_t MaxTries = 10;
+ const auto size = output.size();
std::size_t tries = 0;
- std::array<u8, 5> buffer = {0x00, 0x00, 0x00, 0x00, size};
- std::vector<u8> local_buffer(size + 20);
+ std::array<u8, 5> buffer = {0x00, 0x00, 0x00, 0x00, static_cast<u8>(size)};
+ std::vector<u8> local_buffer{};
buffer[0] = static_cast<u8>(static_cast<u16>(addr) & 0x00FF);
buffer[1] = static_cast<u8>((static_cast<u16>(addr) & 0xFF00) >> 8);
@@ -167,8 +169,12 @@ DriverResult JoyconCommonProtocol::ReadSPI(CalAddr addr, u8 size, std::vector<u8
}
} while (local_buffer[15] != buffer[0] || local_buffer[16] != buffer[1]);
+ if (local_buffer.size() < size + HeaderSize) {
+ return DriverResult::WrongReply;
+ }
+
// Remove header from output
- output = std::vector<u8>(local_buffer.begin() + 20, local_buffer.begin() + 20 + size);
+ memcpy(output.data(), local_buffer.data() + HeaderSize, size);
return DriverResult::Success;
}
diff --git a/src/input_common/helpers/joycon_protocol/common_protocol.h b/src/input_common/helpers/joycon_protocol/common_protocol.h
index 903bcf402..75d3f20a4 100644
--- a/src/input_common/helpers/joycon_protocol/common_protocol.h
+++ b/src/input_common/helpers/joycon_protocol/common_protocol.h
@@ -97,10 +97,29 @@ public:
/**
* Reads the SPI memory stored on the joycon
* @param Initial address location
- * @param size in bytes to be read
* @returns output buffer containing the responce
*/
- DriverResult ReadSPI(CalAddr addr, u8 size, std::vector<u8>& output);
+ DriverResult ReadRawSPI(SpiAddress addr, std::span<u8> output);
+
+ /**
+ * Reads the SPI memory stored on the joycon
+ * @param Initial address location
+ * @returns output object containing the responce
+ */
+ template <typename Output>
+ requires std::is_trivially_copyable_v<Output> DriverResult ReadSPI(SpiAddress addr,
+ Output& output) {
+ std::array<u8, sizeof(Output)> buffer;
+ output = {};
+
+ const auto result = ReadRawSPI(addr, buffer);
+ if (result != DriverResult::Success) {
+ return result;
+ }
+
+ std::memcpy(&output, buffer.data(), sizeof(Output));
+ return DriverResult::Success;
+ }
/**
* Enables MCU chip on the joycon
diff --git a/src/input_common/helpers/joycon_protocol/generic_functions.cpp b/src/input_common/helpers/joycon_protocol/generic_functions.cpp
index 63cfb1369..484c208e6 100644
--- a/src/input_common/helpers/joycon_protocol/generic_functions.cpp
+++ b/src/input_common/helpers/joycon_protocol/generic_functions.cpp
@@ -71,8 +71,8 @@ DriverResult GenericProtocol::GetBattery(u32& battery_level) {
DriverResult GenericProtocol::GetColor(Color& color) {
ScopedSetBlocking sb(this);
- std::vector<u8> buffer;
- const auto result = ReadSPI(CalAddr::COLOR_DATA, 12, buffer);
+ std::array<u8, 12> buffer{};
+ const auto result = ReadRawSPI(SpiAddress::COLOR_DATA, buffer);
color = {};
if (result == DriverResult::Success) {
@@ -87,8 +87,8 @@ DriverResult GenericProtocol::GetColor(Color& color) {
DriverResult GenericProtocol::GetSerialNumber(SerialNumber& serial_number) {
ScopedSetBlocking sb(this);
- std::vector<u8> buffer;
- const auto result = ReadSPI(CalAddr::SERIAL_NUMBER, 16, buffer);
+ std::array<u8, 16> buffer{};
+ const auto result = ReadRawSPI(SpiAddress::SERIAL_NUMBER, buffer);
serial_number = {};
if (result == DriverResult::Success) {
diff --git a/src/input_common/helpers/joycon_protocol/joycon_types.h b/src/input_common/helpers/joycon_protocol/joycon_types.h
index 182d2c15b..14b07bfb5 100644
--- a/src/input_common/helpers/joycon_protocol/joycon_types.h
+++ b/src/input_common/helpers/joycon_protocol/joycon_types.h
@@ -159,13 +159,12 @@ enum class UsbSubCommand : u8 {
SEND_UART = 0x92,
};
-enum class CalMagic : u8 {
+enum class CalibrationMagic : u8 {
USR_MAGIC_0 = 0xB2,
USR_MAGIC_1 = 0xA1,
- USRR_MAGI_SIZE = 2,
};
-enum class CalAddr {
+enum class SpiAddress {
SERIAL_NUMBER = 0X6000,
DEVICE_TYPE = 0X6012,
COLOR_EXIST = 0X601B,
@@ -396,10 +395,35 @@ struct MotionData {
u64 delta_timestamp{};
};
+// Output from SPI read command containing user calibration magic
+struct MagicSpiCalibration {
+ CalibrationMagic first;
+ CalibrationMagic second;
+};
+static_assert(sizeof(MagicSpiCalibration) == 0x2, "MagicSpiCalibration is an invalid size");
+
+// Output from SPI read command containing left joystick calibration
+struct JoystickLeftSpiCalibration {
+ std::array<u8, 3> max;
+ std::array<u8, 3> center;
+ std::array<u8, 3> min;
+};
+static_assert(sizeof(JoystickLeftSpiCalibration) == 0x9,
+ "JoystickLeftSpiCalibration is an invalid size");
+
+// Output from SPI read command containing right joystick calibration
+struct JoystickRightSpiCalibration {
+ std::array<u8, 3> center;
+ std::array<u8, 3> min;
+ std::array<u8, 3> max;
+};
+static_assert(sizeof(JoystickRightSpiCalibration) == 0x9,
+ "JoystickRightSpiCalibration is an invalid size");
+
struct JoyStickAxisCalibration {
- u16 max{1};
- u16 min{1};
- u16 center{0};
+ u16 max;
+ u16 min;
+ u16 center;
};
struct JoyStickCalibration {
@@ -407,6 +431,14 @@ struct JoyStickCalibration {
JoyStickAxisCalibration y;
};
+struct ImuSpiCalibration {
+ std::array<s16, 3> accelerometer_offset;
+ std::array<s16, 3> accelerometer_scale;
+ std::array<s16, 3> gyroscope_offset;
+ std::array<s16, 3> gyroscope_scale;
+};
+static_assert(sizeof(ImuSpiCalibration) == 0x18, "ImuSpiCalibration is an invalid size");
+
struct RingCalibration {
s16 default_value;
s16 max_value;
@@ -488,14 +520,6 @@ struct InputReportNfcIr {
static_assert(sizeof(InputReportNfcIr) == 0x29, "InputReportNfcIr is an invalid size");
#pragma pack(pop)
-struct IMUCalibration {
- std::array<s16, 3> accelerometer_offset;
- std::array<s16, 3> accelerometer_scale;
- std::array<s16, 3> gyroscope_offset;
- std::array<s16, 3> gyroscope_scale;
-};
-static_assert(sizeof(IMUCalibration) == 0x18, "IMUCalibration is an invalid size");
-
struct NFCReadBlock {
u8 start;
u8 end;
diff --git a/src/shader_recompiler/backend/glasm/emit_glasm.cpp b/src/shader_recompiler/backend/glasm/emit_glasm.cpp
index 0cb1e193e..fd4a61a4d 100644
--- a/src/shader_recompiler/backend/glasm/emit_glasm.cpp
+++ b/src/shader_recompiler/backend/glasm/emit_glasm.cpp
@@ -279,6 +279,8 @@ void SetupOptions(const IR::Program& program, const Profile& profile,
header += "OPTION NV_internal;"
"OPTION NV_shader_storage_buffer;"
"OPTION NV_gpu_program_fp64;";
+ // TODO: Enable only when MS is used
+ header += "OPTION NV_texture_multisample;";
if (info.uses_int64_bit_atomics) {
header += "OPTION NV_shader_atomic_int64;";
}
diff --git a/src/shader_recompiler/backend/glasm/emit_glasm_bitwise_conversion.cpp b/src/shader_recompiler/backend/glasm/emit_glasm_bitwise_conversion.cpp
index 5bfdecc09..2fc2a0ac6 100644
--- a/src/shader_recompiler/backend/glasm/emit_glasm_bitwise_conversion.cpp
+++ b/src/shader_recompiler/backend/glasm/emit_glasm_bitwise_conversion.cpp
@@ -43,10 +43,6 @@ void EmitBitCastU64F64(EmitContext&, IR::Inst& inst, const IR::Value& value) {
Alias(inst, value);
}
-void EmitBitCastS32F32(EmitContext&, IR::Inst& inst, const IR::Value& value) {
- Alias(inst, value);
-}
-
void EmitBitCastF16U16(EmitContext&, IR::Inst& inst, const IR::Value& value) {
Alias(inst, value);
}
diff --git a/src/shader_recompiler/backend/glasm/emit_glasm_image.cpp b/src/shader_recompiler/backend/glasm/emit_glasm_image.cpp
index e67e80fac..cf6065208 100644
--- a/src/shader_recompiler/backend/glasm/emit_glasm_image.cpp
+++ b/src/shader_recompiler/backend/glasm/emit_glasm_image.cpp
@@ -59,7 +59,7 @@ std::string Image(EmitContext& ctx, IR::TextureInstInfo info,
}
}
-std::string_view TextureType(IR::TextureInstInfo info) {
+std::string_view TextureType(IR::TextureInstInfo info, bool is_ms = false) {
if (info.is_depth) {
switch (info.type) {
case TextureType::Color1D:
@@ -88,9 +88,9 @@ std::string_view TextureType(IR::TextureInstInfo info) {
return "ARRAY1D";
case TextureType::Color2D:
case TextureType::Color2DRect:
- return "2D";
+ return is_ms ? "2DMS" : "2D";
case TextureType::ColorArray2D:
- return "ARRAY2D";
+ return is_ms ? "ARRAY2DMS" : "ARRAY2D";
case TextureType::Color3D:
return "3D";
case TextureType::ColorCube:
@@ -510,15 +510,16 @@ void EmitImageFetch(EmitContext& ctx, IR::Inst& inst, const IR::Value& index,
const IR::Value& coord, const IR::Value& offset, ScalarS32 lod, ScalarS32 ms) {
const auto info{inst.Flags<IR::TextureInstInfo>()};
const auto sparse_inst{PrepareSparse(inst)};
+ const bool is_multisample{ms.type != Type::Void};
const std::string_view sparse_mod{sparse_inst ? ".SPARSE" : ""};
- const std::string_view type{TextureType(info)};
+ const std::string_view type{TextureType(info, is_multisample)};
const std::string texture{Texture(ctx, info, index)};
const std::string offset_vec{Offset(ctx, offset)};
const auto [coord_vec, coord_alloc]{Coord(ctx, coord)};
const Register ret{ctx.reg_alloc.Define(inst)};
if (info.type == TextureType::Buffer) {
ctx.Add("TXF.F{} {},{},{},{}{};", sparse_mod, ret, coord_vec, texture, type, offset_vec);
- } else if (ms.type != Type::Void) {
+ } else if (is_multisample) {
ctx.Add("MOV.S {}.w,{};"
"TXFMS.F{} {},{},{},{}{};",
coord_vec, ms, sparse_mod, ret, coord_vec, texture, type, offset_vec);
diff --git a/src/shader_recompiler/backend/glasm/emit_glasm_instructions.h b/src/shader_recompiler/backend/glasm/emit_glasm_instructions.h
index eaaf9ba39..415a249e4 100644
--- a/src/shader_recompiler/backend/glasm/emit_glasm_instructions.h
+++ b/src/shader_recompiler/backend/glasm/emit_glasm_instructions.h
@@ -197,7 +197,6 @@ void EmitSelectF64(EmitContext& ctx, ScalarS32 cond, Register true_value, Regist
void EmitBitCastU16F16(EmitContext& ctx, IR::Inst& inst, const IR::Value& value);
void EmitBitCastU32F32(EmitContext& ctx, IR::Inst& inst, const IR::Value& value);
void EmitBitCastU64F64(EmitContext& ctx, IR::Inst& inst, const IR::Value& value);
-void EmitBitCastS32F32(EmitContext& ctx, IR::Inst& inst, const IR::Value& value);
void EmitBitCastF16U16(EmitContext& ctx, IR::Inst& inst, const IR::Value& value);
void EmitBitCastF32U32(EmitContext& ctx, IR::Inst& inst, const IR::Value& value);
void EmitBitCastF64U64(EmitContext& ctx, IR::Inst& inst, const IR::Value& value);
diff --git a/src/shader_recompiler/backend/glsl/emit_glsl_bitwise_conversion.cpp b/src/shader_recompiler/backend/glsl/emit_glsl_bitwise_conversion.cpp
index 8e5e6cf1f..1be4a0f59 100644
--- a/src/shader_recompiler/backend/glsl/emit_glsl_bitwise_conversion.cpp
+++ b/src/shader_recompiler/backend/glsl/emit_glsl_bitwise_conversion.cpp
@@ -48,10 +48,6 @@ void EmitBitCastU64F64(EmitContext& ctx, IR::Inst& inst, std::string_view value)
ctx.AddU64("{}=doubleBitsToUint64({});", inst, value);
}
-void EmitBitCastS32F32(EmitContext& ctx, IR::Inst& inst, std::string_view value) {
- ctx.AddF32("{}=ftoi({});", inst, value);
-}
-
void EmitBitCastF16U16([[maybe_unused]] EmitContext& ctx, [[maybe_unused]] IR::Inst& inst) {
NotImplemented();
}
diff --git a/src/shader_recompiler/backend/glsl/emit_glsl_image.cpp b/src/shader_recompiler/backend/glsl/emit_glsl_image.cpp
index cecdbb9d6..d8874b0cc 100644
--- a/src/shader_recompiler/backend/glsl/emit_glsl_image.cpp
+++ b/src/shader_recompiler/backend/glsl/emit_glsl_image.cpp
@@ -414,7 +414,7 @@ void EmitImageGatherDref(EmitContext& ctx, IR::Inst& inst, const IR::Value& inde
void EmitImageFetch(EmitContext& ctx, IR::Inst& inst, const IR::Value& index,
std::string_view coords, std::string_view offset, std::string_view lod,
- [[maybe_unused]] std::string_view ms) {
+ std::string_view ms) {
const auto info{inst.Flags<IR::TextureInstInfo>()};
if (info.has_bias) {
throw NotImplementedException("EmitImageFetch Bias texture samples");
@@ -431,19 +431,24 @@ void EmitImageFetch(EmitContext& ctx, IR::Inst& inst, const IR::Value& index,
ctx.AddU1("{}=true;", *sparse_inst);
}
if (!sparse_inst || !supports_sparse) {
- if (!offset.empty()) {
- ctx.Add("{}=texelFetchOffset({},{},int({}),{});", texel, texture,
- CoordsCastToInt(coords, info), lod, CoordsCastToInt(offset, info));
+ const auto int_coords{CoordsCastToInt(coords, info)};
+ if (!ms.empty()) {
+ ctx.Add("{}=texelFetch({},{},int({}));", texel, texture, int_coords, ms);
+ } else if (!offset.empty()) {
+ ctx.Add("{}=texelFetchOffset({},{},int({}),{});", texel, texture, int_coords, lod,
+ CoordsCastToInt(offset, info));
} else {
if (info.type == TextureType::Buffer) {
ctx.Add("{}=texelFetch({},int({}));", texel, texture, coords);
} else {
- ctx.Add("{}=texelFetch({},{},int({}));", texel, texture,
- CoordsCastToInt(coords, info), lod);
+ ctx.Add("{}=texelFetch({},{},int({}));", texel, texture, int_coords, lod);
}
}
return;
}
+ if (!ms.empty()) {
+ throw NotImplementedException("EmitImageFetch Sparse MSAA samples");
+ }
if (!offset.empty()) {
ctx.AddU1("{}=sparseTexelsResidentARB(sparseTexelFetchOffsetARB({},{},int({}),{},{}));",
*sparse_inst, texture, CastToIntVec(coords, info), lod,
diff --git a/src/shader_recompiler/backend/glsl/emit_glsl_instructions.h b/src/shader_recompiler/backend/glsl/emit_glsl_instructions.h
index 4151c89de..c6df1dba7 100644
--- a/src/shader_recompiler/backend/glsl/emit_glsl_instructions.h
+++ b/src/shader_recompiler/backend/glsl/emit_glsl_instructions.h
@@ -231,7 +231,6 @@ void EmitSelectF64(EmitContext& ctx, IR::Inst& inst, std::string_view cond,
void EmitBitCastU16F16(EmitContext& ctx, IR::Inst& inst);
void EmitBitCastU32F32(EmitContext& ctx, IR::Inst& inst, std::string_view value);
void EmitBitCastU64F64(EmitContext& ctx, IR::Inst& inst, std::string_view value);
-void EmitBitCastS32F32(EmitContext& ctx, IR::Inst& inst, std::string_view value);
void EmitBitCastF16U16(EmitContext& ctx, IR::Inst& inst);
void EmitBitCastF32U32(EmitContext& ctx, IR::Inst& inst, std::string_view value);
void EmitBitCastF64U64(EmitContext& ctx, IR::Inst& inst, std::string_view value);
diff --git a/src/shader_recompiler/backend/glsl/glsl_emit_context.cpp b/src/shader_recompiler/backend/glsl/glsl_emit_context.cpp
index 5d01ec0cd..1b006e811 100644
--- a/src/shader_recompiler/backend/glsl/glsl_emit_context.cpp
+++ b/src/shader_recompiler/backend/glsl/glsl_emit_context.cpp
@@ -61,24 +61,28 @@ std::string OutputDecorator(Stage stage, u32 size) {
}
}
-std::string_view SamplerType(TextureType type, bool is_depth) {
- if (is_depth) {
- switch (type) {
- case TextureType::Color1D:
- return "sampler1DShadow";
- case TextureType::ColorArray1D:
- return "sampler1DArrayShadow";
- case TextureType::Color2D:
- return "sampler2DShadow";
- case TextureType::ColorArray2D:
- return "sampler2DArrayShadow";
- case TextureType::ColorCube:
- return "samplerCubeShadow";
- case TextureType::ColorArrayCube:
- return "samplerCubeArrayShadow";
- default:
- throw NotImplementedException("Texture type: {}", type);
- }
+std::string_view DepthSamplerType(TextureType type) {
+ switch (type) {
+ case TextureType::Color1D:
+ return "sampler1DShadow";
+ case TextureType::ColorArray1D:
+ return "sampler1DArrayShadow";
+ case TextureType::Color2D:
+ return "sampler2DShadow";
+ case TextureType::ColorArray2D:
+ return "sampler2DArrayShadow";
+ case TextureType::ColorCube:
+ return "samplerCubeShadow";
+ case TextureType::ColorArrayCube:
+ return "samplerCubeArrayShadow";
+ default:
+ throw NotImplementedException("Texture type: {}", type);
+ }
+}
+
+std::string_view ColorSamplerType(TextureType type, bool is_multisample = false) {
+ if (is_multisample) {
+ ASSERT(type == TextureType::Color2D || type == TextureType::ColorArray2D);
}
switch (type) {
case TextureType::Color1D:
@@ -87,9 +91,9 @@ std::string_view SamplerType(TextureType type, bool is_depth) {
return "sampler1DArray";
case TextureType::Color2D:
case TextureType::Color2DRect:
- return "sampler2D";
+ return is_multisample ? "sampler2DMS" : "sampler2D";
case TextureType::ColorArray2D:
- return "sampler2DArray";
+ return is_multisample ? "sampler2DMSArray" : "sampler2DArray";
case TextureType::Color3D:
return "sampler3D";
case TextureType::ColorCube:
@@ -677,7 +681,7 @@ void EmitContext::SetupTextures(Bindings& bindings) {
texture_buffers.reserve(info.texture_buffer_descriptors.size());
for (const auto& desc : info.texture_buffer_descriptors) {
texture_buffers.push_back({bindings.texture, desc.count});
- const auto sampler_type{SamplerType(TextureType::Buffer, false)};
+ const auto sampler_type{ColorSamplerType(TextureType::Buffer)};
const auto array_decorator{desc.count > 1 ? fmt::format("[{}]", desc.count) : ""};
header += fmt::format("layout(binding={}) uniform {} tex{}{};", bindings.texture,
sampler_type, bindings.texture, array_decorator);
@@ -686,7 +690,8 @@ void EmitContext::SetupTextures(Bindings& bindings) {
textures.reserve(info.texture_descriptors.size());
for (const auto& desc : info.texture_descriptors) {
textures.push_back({bindings.texture, desc.count});
- const auto sampler_type{SamplerType(desc.type, desc.is_depth)};
+ const auto sampler_type{desc.is_depth ? DepthSamplerType(desc.type)
+ : ColorSamplerType(desc.type, desc.is_multisample)};
const auto array_decorator{desc.count > 1 ? fmt::format("[{}]", desc.count) : ""};
header += fmt::format("layout(binding={}) uniform {} tex{}{};", bindings.texture,
sampler_type, bindings.texture, array_decorator);
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_bitwise_conversion.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_bitwise_conversion.cpp
index 50daacd95..c4ca28d11 100644
--- a/src/shader_recompiler/backend/spirv/emit_spirv_bitwise_conversion.cpp
+++ b/src/shader_recompiler/backend/spirv/emit_spirv_bitwise_conversion.cpp
@@ -18,10 +18,6 @@ void EmitBitCastU64F64(EmitContext&) {
throw NotImplementedException("SPIR-V Instruction");
}
-void EmitBitCastS32F32(EmitContext&) {
- throw NotImplementedException("SPIR-V Instruction");
-}
-
void EmitBitCastF16U16(EmitContext&) {
throw NotImplementedException("SPIR-V Instruction");
}
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_instructions.h b/src/shader_recompiler/backend/spirv/emit_spirv_instructions.h
index e31cdc5e8..db12e8176 100644
--- a/src/shader_recompiler/backend/spirv/emit_spirv_instructions.h
+++ b/src/shader_recompiler/backend/spirv/emit_spirv_instructions.h
@@ -179,7 +179,6 @@ Id EmitSelectF64(EmitContext& ctx, Id cond, Id true_value, Id false_value);
void EmitBitCastU16F16(EmitContext& ctx);
Id EmitBitCastU32F32(EmitContext& ctx, Id value);
void EmitBitCastU64F64(EmitContext& ctx);
-void EmitBitCastS32F32(EmitContext& ctx);
void EmitBitCastF16U16(EmitContext&);
Id EmitBitCastF32U32(EmitContext& ctx, Id value);
void EmitBitCastF64U64(EmitContext& ctx);
diff --git a/src/shader_recompiler/frontend/ir/ir_emitter.cpp b/src/shader_recompiler/frontend/ir/ir_emitter.cpp
index eb2e49a68..430797d23 100644
--- a/src/shader_recompiler/frontend/ir/ir_emitter.cpp
+++ b/src/shader_recompiler/frontend/ir/ir_emitter.cpp
@@ -704,11 +704,6 @@ IR::U32 IREmitter::BitCast<IR::U32, IR::F32>(const IR::F32& value) {
}
template <>
-IR::S32 IREmitter::BitCast<IR::S32, IR::F32>(const IR::F32& value) {
- return Inst<IR::S32>(Opcode::BitCastS32F32, value);
-}
-
-template <>
IR::F32 IREmitter::BitCast<IR::F32, IR::U32>(const IR::U32& value) {
return Inst<IR::F32>(Opcode::BitCastF32U32, value);
}
diff --git a/src/shader_recompiler/frontend/ir/opcodes.h b/src/shader_recompiler/frontend/ir/opcodes.h
index d155afd0f..e300714f3 100644
--- a/src/shader_recompiler/frontend/ir/opcodes.h
+++ b/src/shader_recompiler/frontend/ir/opcodes.h
@@ -38,7 +38,6 @@ constexpr Type U8{Type::U8};
constexpr Type U16{Type::U16};
constexpr Type U32{Type::U32};
constexpr Type U64{Type::U64};
-constexpr Type S32{Type::S32};
constexpr Type F16{Type::F16};
constexpr Type F32{Type::F32};
constexpr Type F64{Type::F64};
diff --git a/src/shader_recompiler/frontend/ir/opcodes.inc b/src/shader_recompiler/frontend/ir/opcodes.inc
index 1fe3749cc..24e82f802 100644
--- a/src/shader_recompiler/frontend/ir/opcodes.inc
+++ b/src/shader_recompiler/frontend/ir/opcodes.inc
@@ -175,7 +175,6 @@ OPCODE(SelectF64, F64, U1,
OPCODE(BitCastU16F16, U16, F16, )
OPCODE(BitCastU32F32, U32, F32, )
OPCODE(BitCastU64F64, U64, F64, )
-OPCODE(BitCastS32F32, S32, F32, )
OPCODE(BitCastF16U16, F16, U16, )
OPCODE(BitCastF32U32, F32, U32, )
OPCODE(BitCastF64U64, F64, U64, )
diff --git a/src/shader_recompiler/frontend/ir/type.h b/src/shader_recompiler/frontend/ir/type.h
index 5a7c706ad..04c8c4ddb 100644
--- a/src/shader_recompiler/frontend/ir/type.h
+++ b/src/shader_recompiler/frontend/ir/type.h
@@ -24,22 +24,21 @@ enum class Type {
U16 = 1 << 7,
U32 = 1 << 8,
U64 = 1 << 9,
- S32 = 1 << 10,
- F16 = 1 << 11,
- F32 = 1 << 12,
- F64 = 1 << 13,
- U32x2 = 1 << 14,
- U32x3 = 1 << 15,
- U32x4 = 1 << 16,
- F16x2 = 1 << 17,
- F16x3 = 1 << 18,
- F16x4 = 1 << 19,
- F32x2 = 1 << 20,
- F32x3 = 1 << 21,
- F32x4 = 1 << 22,
- F64x2 = 1 << 23,
- F64x3 = 1 << 24,
- F64x4 = 1 << 25,
+ F16 = 1 << 10,
+ F32 = 1 << 11,
+ F64 = 1 << 12,
+ U32x2 = 1 << 13,
+ U32x3 = 1 << 14,
+ U32x4 = 1 << 15,
+ F16x2 = 1 << 16,
+ F16x3 = 1 << 17,
+ F16x4 = 1 << 18,
+ F32x2 = 1 << 19,
+ F32x3 = 1 << 20,
+ F32x4 = 1 << 21,
+ F64x2 = 1 << 22,
+ F64x3 = 1 << 23,
+ F64x4 = 1 << 24,
};
DECLARE_ENUM_FLAG_OPERATORS(Type)
diff --git a/src/shader_recompiler/frontend/ir/value.cpp b/src/shader_recompiler/frontend/ir/value.cpp
index 30ba12316..346169328 100644
--- a/src/shader_recompiler/frontend/ir/value.cpp
+++ b/src/shader_recompiler/frontend/ir/value.cpp
@@ -23,8 +23,6 @@ Value::Value(u16 value) noexcept : type{Type::U16}, imm_u16{value} {}
Value::Value(u32 value) noexcept : type{Type::U32}, imm_u32{value} {}
-Value::Value(s32 value) noexcept : type{Type::S32}, imm_s32{value} {}
-
Value::Value(f32 value) noexcept : type{Type::F32}, imm_f32{value} {}
Value::Value(u64 value) noexcept : type{Type::U64}, imm_u64{value} {}
@@ -71,7 +69,6 @@ bool Value::operator==(const Value& other) const {
return imm_u16 == other.imm_u16;
case Type::U32:
case Type::F32:
- case Type::S32:
return imm_u32 == other.imm_u32;
case Type::U64:
case Type::F64:
diff --git a/src/shader_recompiler/frontend/ir/value.h b/src/shader_recompiler/frontend/ir/value.h
index 8b34356fd..883dfa24e 100644
--- a/src/shader_recompiler/frontend/ir/value.h
+++ b/src/shader_recompiler/frontend/ir/value.h
@@ -268,7 +268,6 @@ using U8 = TypedValue<Type::U8>;
using U16 = TypedValue<Type::U16>;
using U32 = TypedValue<Type::U32>;
using U64 = TypedValue<Type::U64>;
-using S32 = TypedValue<Type::S32>;
using F16 = TypedValue<Type::F16>;
using F32 = TypedValue<Type::F32>;
using F64 = TypedValue<Type::F64>;
diff --git a/src/shader_recompiler/ir_opt/texture_pass.cpp b/src/shader_recompiler/ir_opt/texture_pass.cpp
index 9718c6921..70b620dcb 100644
--- a/src/shader_recompiler/ir_opt/texture_pass.cpp
+++ b/src/shader_recompiler/ir_opt/texture_pass.cpp
@@ -486,10 +486,10 @@ void PatchTexelFetch(IR::Block& block, IR::Inst& inst, TexturePixelFormat pixel_
const IR::F32 w(ir.CompositeExtract(new_inst, 3));
const IR::F16F32F64 max_value(ir.Imm32(get_max_value()));
const IR::Value converted =
- ir.CompositeConstruct(ir.FPMul(ir.ConvertSToF(32, 32, ir.BitCast<IR::S32>(x)), max_value),
- ir.FPMul(ir.ConvertSToF(32, 32, ir.BitCast<IR::S32>(y)), max_value),
- ir.FPMul(ir.ConvertSToF(32, 32, ir.BitCast<IR::S32>(z)), max_value),
- ir.FPMul(ir.ConvertSToF(32, 32, ir.BitCast<IR::S32>(w)), max_value));
+ ir.CompositeConstruct(ir.FPMul(ir.ConvertSToF(32, 32, ir.BitCast<IR::U32>(x)), max_value),
+ ir.FPMul(ir.ConvertSToF(32, 32, ir.BitCast<IR::U32>(y)), max_value),
+ ir.FPMul(ir.ConvertSToF(32, 32, ir.BitCast<IR::U32>(z)), max_value),
+ ir.FPMul(ir.ConvertSToF(32, 32, ir.BitCast<IR::U32>(w)), max_value));
inst.ReplaceUsesWith(converted);
}
} // Anonymous namespace
diff --git a/src/video_core/texture_cache/image_info.cpp b/src/video_core/texture_cache/image_info.cpp
index 852ec2519..e9100091e 100644
--- a/src/video_core/texture_cache/image_info.cpp
+++ b/src/video_core/texture_cache/image_info.cpp
@@ -100,6 +100,10 @@ ImageInfo::ImageInfo(const TICEntry& config) noexcept {
ASSERT_MSG(false, "Invalid texture_type={}", static_cast<int>(config.texture_type.Value()));
break;
}
+ if (num_samples > 1) {
+ size.width *= NumSamplesX(config.msaa_mode);
+ size.height *= NumSamplesY(config.msaa_mode);
+ }
if (type != ImageType::Linear) {
// FIXME: Call this without passing *this
layer_stride = CalculateLayerStride(*this);
diff --git a/src/video_core/texture_cache/samples_helper.h b/src/video_core/texture_cache/samples_helper.h
index d552bccf0..203ac1b11 100644
--- a/src/video_core/texture_cache/samples_helper.h
+++ b/src/video_core/texture_cache/samples_helper.h
@@ -51,4 +51,48 @@ namespace VideoCommon {
return 1;
}
+[[nodiscard]] inline int NumSamplesX(Tegra::Texture::MsaaMode msaa_mode) {
+ using Tegra::Texture::MsaaMode;
+ switch (msaa_mode) {
+ case MsaaMode::Msaa1x1:
+ return 1;
+ case MsaaMode::Msaa2x1:
+ case MsaaMode::Msaa2x1_D3D:
+ case MsaaMode::Msaa2x2:
+ case MsaaMode::Msaa2x2_VC4:
+ case MsaaMode::Msaa2x2_VC12:
+ return 2;
+ case MsaaMode::Msaa4x2:
+ case MsaaMode::Msaa4x2_D3D:
+ case MsaaMode::Msaa4x2_VC8:
+ case MsaaMode::Msaa4x2_VC24:
+ case MsaaMode::Msaa4x4:
+ return 4;
+ }
+ ASSERT_MSG(false, "Invalid MSAA mode={}", static_cast<int>(msaa_mode));
+ return 1;
+}
+
+[[nodiscard]] inline int NumSamplesY(Tegra::Texture::MsaaMode msaa_mode) {
+ using Tegra::Texture::MsaaMode;
+ switch (msaa_mode) {
+ case MsaaMode::Msaa1x1:
+ case MsaaMode::Msaa2x1:
+ case MsaaMode::Msaa2x1_D3D:
+ return 1;
+ case MsaaMode::Msaa2x2:
+ case MsaaMode::Msaa2x2_VC4:
+ case MsaaMode::Msaa2x2_VC12:
+ case MsaaMode::Msaa4x2:
+ case MsaaMode::Msaa4x2_D3D:
+ case MsaaMode::Msaa4x2_VC8:
+ case MsaaMode::Msaa4x2_VC24:
+ return 2;
+ case MsaaMode::Msaa4x4:
+ return 4;
+ }
+ ASSERT_MSG(false, "Invalid MSAA mode={}", static_cast<int>(msaa_mode));
+ return 1;
+}
+
} // namespace VideoCommon
diff --git a/src/yuzu/configuration/input_profiles.cpp b/src/yuzu/configuration/input_profiles.cpp
index 9bb69cab1..41ef4250a 100644
--- a/src/yuzu/configuration/input_profiles.cpp
+++ b/src/yuzu/configuration/input_profiles.cpp
@@ -58,13 +58,16 @@ std::vector<std::string> InputProfiles::GetInputProfileNames() {
std::vector<std::string> profile_names;
profile_names.reserve(map_profiles.size());
- for (const auto& [profile_name, config] : map_profiles) {
+ auto it = map_profiles.cbegin();
+ while (it != map_profiles.cend()) {
+ const auto& [profile_name, config] = *it;
if (!ProfileExistsInFilesystem(profile_name)) {
- DeleteProfile(profile_name);
+ it = map_profiles.erase(it);
continue;
}
profile_names.push_back(profile_name);
+ ++it;
}
std::stable_sort(profile_names.begin(), profile_names.end());
diff --git a/src/yuzu/multiplayer/direct_connect.cpp b/src/yuzu/multiplayer/direct_connect.cpp
index cbd52da85..d71cc23a7 100644
--- a/src/yuzu/multiplayer/direct_connect.cpp
+++ b/src/yuzu/multiplayer/direct_connect.cpp
@@ -81,20 +81,13 @@ void DirectConnectWindow::Connect() {
}
}
}
- switch (static_cast<ConnectionType>(ui->connection_type->currentIndex())) {
- case ConnectionType::TraversalServer:
- break;
- case ConnectionType::IP:
- if (!ui->ip->hasAcceptableInput()) {
- NetworkMessage::ErrorManager::ShowError(
- NetworkMessage::ErrorManager::IP_ADDRESS_NOT_VALID);
- return;
- }
- if (!ui->port->hasAcceptableInput()) {
- NetworkMessage::ErrorManager::ShowError(NetworkMessage::ErrorManager::PORT_NOT_VALID);
- return;
- }
- break;
+ if (!ui->ip->hasAcceptableInput()) {
+ NetworkMessage::ErrorManager::ShowError(NetworkMessage::ErrorManager::IP_ADDRESS_NOT_VALID);
+ return;
+ }
+ if (!ui->port->hasAcceptableInput()) {
+ NetworkMessage::ErrorManager::ShowError(NetworkMessage::ErrorManager::PORT_NOT_VALID);
+ return;
}
// Store settings
diff --git a/src/yuzu/multiplayer/direct_connect.ui b/src/yuzu/multiplayer/direct_connect.ui
index 57d6ec25a..0dd4e6829 100644
--- a/src/yuzu/multiplayer/direct_connect.ui
+++ b/src/yuzu/multiplayer/direct_connect.ui
@@ -27,19 +27,10 @@
<number>0</number>
</property>
<item>
- <widget class="QComboBox" name="connection_type">
- <item>
- <property name="text">
- <string>IP Address</string>
- </property>
- </item>
- </widget>
- </item>
- <item>
<widget class="QWidget" name="ip_container" native="true">
<layout class="QHBoxLayout" name="ip_layout">
<property name="leftMargin">
- <number>5</number>
+ <number>0</number>
</property>
<property name="topMargin">
<number>0</number>
@@ -53,17 +44,17 @@
<item>
<widget class="QLabel" name="label_2">
<property name="text">
- <string>IP</string>
+ <string>Server Address</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="ip">
<property name="toolTip">
- <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;IPv4 address of the host&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+ <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Server address of the host&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="maxLength">
- <number>16</number>
+ <number>253</number>
</property>
</widget>
</item>
@@ -85,6 +76,12 @@
<property name="placeholderText">
<string notr="true" extracomment="placeholder string that tells user default port">24872</string>
</property>
+ <property name="maximumSize">
+ <size>
+ <width>65</width>
+ <height>50</height>
+ </size>
+ </property>
</widget>
</item>
</layout>
diff --git a/src/yuzu/multiplayer/validation.h b/src/yuzu/multiplayer/validation.h
index dd25af280..cbbe6757b 100644
--- a/src/yuzu/multiplayer/validation.h
+++ b/src/yuzu/multiplayer/validation.h
@@ -38,11 +38,28 @@ private:
QRegularExpression(QStringLiteral("^[a-zA-Z0-9._ -]{4,20}"));
QRegularExpressionValidator nickname;
- /// ipv4 address only
- // TODO remove this when we support hostnames in direct connect
+ /// ipv4 / ipv6 / hostnames
QRegularExpression ip_regex = QRegularExpression(QStringLiteral(
- "(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|"
- "2[0-4][0-9]|25[0-5])"));
+ // IPv4 regex
+ "^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$|"
+ // IPv6 regex
+ "^((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|"
+ "(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-"
+ "5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3})|:))|"
+ "(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)"
+ "(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3})|:))|"
+ "(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]"
+ "\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|"
+ "(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2["
+ "0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|"
+ "(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2["
+ "0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|"
+ "(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2["
+ "0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|"
+ "(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?"
+ "\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:)))(%.+)?$|"
+ // Hostname regex
+ "^([a-zA-Z0-9]+(-[a-zA-Z0-9]+)*\\.)+[a-zA-Z]{2,}$"));
QRegularExpressionValidator ip;
/// port must be between 0 and 65535